package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.admin.service.AdChannelService;
import com.heima.admin.service.AdSensitiveService;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.ArticleForEsConstants;
import com.heima.common.exception.CustException;
import com.heima.common.exception.CustomException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Autowired
    WemediaFeign wemediaFeign;

    @Autowired
    ArticleFeign articleFeign;

    @Value("${file.oss.web-site}")
    private String webSite;

    @Autowired
    AdSensitiveService adSensitiveService;

    @Autowired
    AdChannelService adChannelService;

    @Autowired
    GreenTextScan greenTextScan;

    @Autowired
    GreenImageScan greenImageScan;

    @Autowired
    KafkaTemplate kafkaTemplate;

    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //检查参数
        if (wmNewsId == null) {
            log.error("当前的审核ID不能为空");
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = wemediaFeign.findById(wmNewsId).getData();
        if (wmNews == null) {
            log.error("审核的自媒体文章不存在，自媒体的id:{}", wmNewsId);
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE, "当前的审核文章不存在");
        }
        //判断文章的状态,根据状态执行逻辑
        //文章状态=4 人工审核通过，直接保存文章
        //如果人工审核通过且发布时间小于当前时间，直接保存
        if (WmNews.Status.ADMIN_SUCCESS.getCode() == wmNews.getStatus().shortValue()
                && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            //保存数据
            publishArticle(wmNews);
            return;
        }
        //文章状态=8 审核通过 但是发布时间小于等于当前时间，直接保存文章
        if (WmNews.Status.SUCCESS.getCode() == wmNews.getStatus().shortValue()
                && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            //保存数据
            publishArticle(wmNews);
            return;
        }
        //文章状态=1 待审核
        if (WmNews.Status.SUBMIT.getCode() == wmNews.getStatus().shortValue()) {
            // 抽取文章内容中的文本和图片
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);
            //TODO 4.1 自管理敏感词审核
            if (handleSensitive(contentAndImagesResult.get("content").toString(), wmNews)) {
                return;
            }
            //TODO 4.2 阿里云审核文本内容
            if (handleTextScan(contentAndImagesResult.get("content").toString(), wmNews)) {
                return;
            }
            //TODO 4.3 阿里云图片审核
            List<String> images = (List<String>) contentAndImagesResult.get("images");
            if (handleImagesScan(images, wmNews)) {
                return;
            }
            //TODO 4.4 判断文章发布时间大于当前时间，修改状态8
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                updateWmNews(wmNews, WmNews.Status.SUCCESS.getCode(), "文章审核通过，待发布");
                return;
            }
            //TODO 5 保存文章相关数据
            //同步三张表
            publishArticle(wmNews);

            //TODO 6 同步索引库
            //TODO 7 生成文章静态页面
/*            ArticleDto articleDto = new ArticleDto();

            articleFeign.saveArticle(articleDto);*/
        }
    }

    //抽取文章内容中的文本和图片
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        String content = wmNews.getContent();
        //检查文本,不能为空或者超过上限
        if (StringUtils.isBlank(content) || content.length() > 10000) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        List<Map> contentList = JSON.parseArray(content, Map.class);
        //解析文本
        String contents = contentList.stream()
                .filter(x -> x.get("type").equals("text"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.joining("_"));//拼接_,混肴文本
        //拼接标题
        contents = contents + "" + wmNews.getTitle();
        //解析图片
        List<String> images = contentList.stream()
                .filter(x -> x.get("type").equals("image"))
                .map(y -> y.get("value").toString())
                .collect(Collectors.toList());
        //处理封面并拼接
        String imageCover = wmNews.getImages();
        if (StringUtils.isNotBlank(imageCover)) {
            // 添加到内容图片列表
            images.addAll(
                    Stream.of(imageCover.split(","))
                            .map(x -> webSite + x)
                            .collect(Collectors.toList())
            );
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("content", contents);
        resultMap.put("images", images);

        return resultMap;
    }

    /**
     * 自管理敏感词审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = false;
        // 查询所有敏感词
        List<String> adSensitives = adSensitiveService.findAllSensitive();
        // 初始化 DFA搜索
        SensitiveWordUtil.initMap(adSensitives);
        // 匹配敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            flag = true;
            updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文章中包含了敏感词:" + map);
        }
        return flag;
    }

    /**
     * 审核文内容-阿里云
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = false;
        try {
            Map map = greenTextScan.greenTextScan(content);
            //审核不通过
            if (map.get("suggestion").equals("block")) {
                flag = true;
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本中内容有敏感词汇");
            }
            //需要人工审核
            if (map.get("suggestion").equals("review")) {
                flag = true;
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文本中内容需要人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文章阿里云内容审核失败，转入人工审核, e：{}", e);
            flag = true;
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章阿里云内容审核失败,转入需要人工审核");
        }
        return flag;
    }

    /**
     * 图片审核-阿里云
     *
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImagesScan(List<String> images, WmNews wmNews) {

        // 无图则无需审核
        if (images == null || images.size() == 0) {
            return false;
        }

        boolean flag = false;

        try {
            images = images.stream().distinct()
                    .collect(Collectors.toList());
            Map map = greenImageScan.imageUrlScan(images);

            //审核不通过
            if ("block".equals(map.get("suggestion"))) {
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文章图片有违规");
                flag = true;
            }
            //人工审核
            if ("review".equals(map.get("suggestion"))) {
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文章图片有不确定元素");
                flag = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云审核失败，转入人工审核");
            flag = true;
        }

        return flag;
    }

    /**
     * 修改文章
     *
     * @param wmNews
     * @param status
     * @param msg
     */
    private void updateWmNews(WmNews wmNews, Short status, String msg) {
        wmNews.setStatus(status);
        wmNews.setReason(msg);
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);
        if (responseResult.getCode().intValue() != 0) {
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR, responseResult.getErrorMessage());
        }
    }


    /**
     * 发布文章方法
     * @param wmNews
     */
    private void publishArticle(WmNews wmNews) {
        //1. 远程调用saveArticle 保存3张表的信息
        ResponseResult responseResult = saveArticle(wmNews);
        if (responseResult.getCode().intValue()!=0) {
            log.error("远程保存apArticle信息失败： {}",responseResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"远程保存apArticle信息失败");
        }
        //2. 修改自媒体文章状态  9
        wmNews.setArticleId((Long)responseResult.getData());
        updateWmNews(wmNews,(short) 9 ,"发布成功");

        Map map = new HashMap();
        map.put("articleId",wmNews.getArticleId());
        kafkaTemplate.send(ArticleForEsConstants.ARTICLE_ELASTICSEARCH_ADD,JSON.toJSONString(map));
    }
    /**
     * 远程调用feign保存三张表信息
     * @param wmNews
     * @return
     */
    private ResponseResult saveArticle(WmNews wmNews) {
        //1. 封装dto参数
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        // 如果之前没发布过  id为null 发布过为之前关联的articleId
        articleDto.setId(wmNews.getArticleId());
        articleDto.setLayout(wmNews.getType()); // 布局
        if(wmNews.getChannelId()!=null){
            // 设置频道信息
            AdChannel channel = adChannelService.getById(wmNews.getChannelId());
            articleDto.setChannelName(channel.getName());
        }
        // 0 普通文章
        articleDto.setFlag((byte) 0);
        // 自媒体用户id 用于在article服务中查询相关作者信息
        articleDto.setWmUserId(wmNews.getUserId());
        // 远程调用 article微服务保存3张表方法
        return articleFeign.saveArticle(articleDto);
    }
}
